package pilegen;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.filechooser.FileNameExtensionFilter;

public class Environnement {

	public ArrayList<Poignee> pile;
	public ArrayList<Class> types;
	public ArrayList<String> typesprimitifs;
	public ArrayList<Variable> instances;
	public int cptPoignees;
	
	public Environnement(){
		this.pile = new ArrayList<Poignee>();
		this.types = new ArrayList<Class>();
		this.typesprimitifs = new ArrayList<String>();
		this.instances = new ArrayList<Variable>();
		this.cptPoignees = 0;
	}
	
	public Environnement(ArrayList<Poignee> pile, ArrayList<Class> types,
			ArrayList<String> typesprimitifs, ArrayList<Variable> instances,
			int cptPoignees) {
		super();
		this.pile = pile;
		this.types = types;
		this.typesprimitifs = typesprimitifs;
		this.instances = instances;
		this.cptPoignees = cptPoignees;
	}

	public void createVariable(Constructor constr, Object[] cstrargs){
		try{
			String nomvar = constr.getDeclaringClass().getSimpleName()+cptPoignees;
			Object valeur = constr.newInstance(cstrargs);
			Variable newvar = new Variable(nomvar, valeur);
			String nompgn = "p"+cptPoignees;
			Poignee newpgn = new Poignee(newvar, nompgn, cptPoignees);
			newvar.poignees.add(newpgn);
			this.pile.add(newpgn);
			this.instances.add(newvar);
			this.addAttributesToInstances(newvar);
			if(this.hasStaticField(newvar)){
				this.refreshRelatedVariables(newvar);
			}
			cptPoignees++;
		}catch(Exception e){
			System.out.println("L'appel du constructeur "+constr.toString()+" n'a pas fonctionne");
		}
	}
	
	public boolean isDrawable(String classname){
		boolean res = false;
		for(int k=0; k<this.types.size(); k++){
			if(this.types.get(k).getName().equals(classname)){
				res = true;
			}
		}
		return res;
	}
	
	public boolean isPrimitif(String classname){
		boolean isprimitive = false;
		try{
			Class classe = Class.forName(classname);
			isprimitive = classe.isPrimitive();
		}catch(Exception e){
			System.out.println("Classe "+classname+" inexistante");
		}
		boolean isprimitif = false;
		for(int k=0; k<this.typesprimitifs.size(); k++){
			if(this.typesprimitifs.get(k).equals(classname)){
				isprimitif = true;
			}
		}
		boolean res = isprimitive || isprimitif;
		return res;
	}
	
	public static boolean isTypable(Class type){
		boolean res = false;
		String nom = type.getSimpleName();
		String[] typable = {"Integer", "int", "Double", "double", "String"};
		for(String s : typable){
			if(nom.equals(s)){
				res = true;
			}
		}
		return res;
	}
	
	public static String simpleMethodName(Method meth){
		String methstring ;
		String methmod = Modifier.toString(meth.getModifiers());
		String methret = meth.getReturnType().getSimpleName();
		String methname = meth.getName();
		String methargs = "(";
		for(int i=0; i<meth.getParameterTypes().length; i++){
			if(i==0){
				methargs += meth.getParameterTypes()[i].getSimpleName();
			}else{
				methargs += ","+meth.getParameterTypes()[i].getSimpleName();
			}
		}
		methargs += ")";
		methstring = methmod+" "+methret+" "+methname+methargs;
		return methstring;
	}
	
	public static String simpleConstructorName(Constructor constr){
		String constrstring ;
		String constrmod = Modifier.toString(constr.getModifiers());
		String constrname = constr.getDeclaringClass().getSimpleName();
		String constrargs = "(";
		for(int i=0; i<constr.getParameterTypes().length; i++){
			if(i==0){
				constrargs += constr.getParameterTypes()[i].getSimpleName();
			}else{
				constrargs += ","+constr.getParameterTypes()[i].getSimpleName();
			}
		}
		constrargs += ")";
		constrstring = constrmod+" "+constrname+constrargs;
		return constrstring;
	}
	
	public static String trueVariableName(Variable var){
		if(var==null){
			return "null";
		}else{
			if(var.poignees.size()!=0){
				Random rand = new Random();
				int index = rand.nextInt(var.poignees.size());
				return var.poignees.get(index).nom;
			}else{
				if(var.variablesMeres.size()!=0){
					int i=0;
					boolean found = false;
					while((i<var.variablesMeres.size()) && (!found)){
						if(estAccessible(var.variablesMeres.get(i))){
							found = true;
						}else{
							i++;
						}
					}
					if(found){
						String prefixe = trueVariableName(var.variablesMeres.get(i));
						String suffixe = "."+var.attributsPeres.get(i);
						return prefixe+suffixe;
					}else{
						return null;
					}
				}else{
					return null;
				}
			}
		}
	}
	
	public void addAttributesToInstances(Variable var){
		 if(!this.isPrimitif(var.type.getName())){
		//if(!var.type.isPrimitive()){
			//System.out.println("La classe #"+var.type.getName()+"# n'est pas primitive");
			Field[] allFields = Environnement.getAllFields(var.type);
			for(int k=0; k<allFields.length; k++){
				Field attribut_k = allFields[k];
				try{
					/* faut verifier si l'attribut n'est pas partage avec une autre variable 
					 * dans ce cas il ne faudra pas creer de nouvelle variable */
					Object valeurAttribut_k = attribut_k.get(var.valeur);
					if(valeurAttribut_k!=null){
						boolean alreadythere = false;
						int alreadyIndex = 0;
						for(int p=0; p<this.instances.size(); p++){
							if(this.instances.get(p).valeur == valeurAttribut_k){
								alreadythere = true;
								alreadyIndex = p;
							}
						}
						if(!alreadythere){
							/* l'attribut est nouveau donc on l'ajoute a la liste des variables qui seront affichees */
							/* Faudrait pouvoir indiquer dans variablesMeres qu'il s'agit du k-eme attribut de var 
							 * pour afficher ensuite correctement le lien */
							Variable newvar = new Variable(attribut_k.getType(), var.name+"."+attribut_k.getName(), 
									valeurAttribut_k);
							newvar.variablesMeres.add(var);
							newvar.attributsPeres.add(attribut_k.getName());
							this.instances.add(newvar);
							this.addAttributesToInstances(newvar);
							System.out.println("Attribut formant nouvelle variable "+newvar.name);
						}else{
							/* L'attribut existe deja dans l'environnement, il obtient donc une variableMere 
							 * et un attributPere supplementaires */
							this.instances.get(alreadyIndex).variablesMeres.add(var);
							this.instances.get(alreadyIndex).attributsPeres.add(attribut_k.getName());
							System.out.println("Attribut existe deja");
						}
					}
				}catch(Exception e){
					System.out.println("Impossible d'acceder a l'attribut "+attribut_k.getName()
							+" de la variable "+var.name);
				}
			}
		}else{
			System.out.println("La classe "+var.type.getName()+" est primitive");
		}
	}
	
	public void setAttributeNull(String nomVar, String nomAtt){
		Variable var = this.getVariableByName(nomVar);
		if(var!=null){
			/* recherche du Field correspondant au String nomAtt designant d'attribut */
			Field[] attributsVar = Environnement.getAllFields(var.type);
			Field attributRecherche = null;
			for(int i=0; i<attributsVar.length; i++){
				if(attributsVar[i].getName().equals(nomAtt)){
					attributRecherche = attributsVar[i];
				}
			}
			if(attributRecherche!=null){
				/* il faut maintenant trouver dans l'environnement quelle variable contient la valeur
				 * de l'attribut nomAtt de la variable nomVar */
				try{
					Object valeurAtt = attributRecherche.get(var.valeur);
					System.out.println("NO I DON'T WANT TO DISAPPEAR ! "+nomVar+"."+nomAtt+"="+valeurAtt);
					attributRecherche.set(var.valeur, null);
					Variable contientAtt = null;
					for(int i=0; i<this.instances.size(); i++){
						if(this.instances.get(i).valeur == valeurAtt){
							contientAtt = this.instances.get(i);
						}
					}
					if(contientAtt!=null){
						int i=0;
						while(i<contientAtt.variablesMeres.size()){
							if(contientAtt.variablesMeres.get(i).name.equals(nomVar) && 
									contientAtt.attributsPeres.get(i).equals(nomAtt)){
								contientAtt.variablesMeres.remove(i);
								contientAtt.attributsPeres.remove(i);
							}else{
								i++;
							}
						}
					}
					if(Modifier.isStatic(attributRecherche.getModifiers())){
						this.refreshRelatedVariables(var);
					}
				}catch(Exception e){
					System.out.println("Impossible de mettre "+nomVar+"."+nomAtt+" a null");
				}
			}
		}
	}
	
	public void changeAttribute(String attributeName, Variable hasAttribute, Variable newAttribute){
		Field attribute = null;
		Field[] allFields = Environnement.getAllFields(hasAttribute.type);
		/* recherche du Field correspondant au String attributeName */
		for(int i=0; i<allFields.length; i++){
			if(allFields[i].getName().equals(attributeName)){
				attribute = allFields[i];
			}
		}
		if(attribute!=null && attribute.getType().isAssignableFrom(newAttribute.type)){
			/* il faut trouver la Variable correspondant a l'attribut attributeName de hasAttribute */
			try{
				/* il faut retirer hasAttribute de l'attribut classesMeres de la variable ayant pour valeur
				 * l'attribut attributeName de hasAttribute */
				Variable oldAttribute = null;
				for(int i=0; i<this.instances.size(); i++){
					Variable var_i = this.instances.get(i);
					for(int j=0; j<var_i.variablesMeres.size(); j++){
						if(var_i.variablesMeres.get(j).name.equals(hasAttribute.name) 
								&& var_i.attributsPeres.get(j).equals(attribute.getName())){
							oldAttribute = var_i;
						}
					}
				}
				if(oldAttribute!=null){
					/* la variable ayant pour valeur hasAttribute.valeur.attributeName existe bien */
					this.retireVariableMere(attributeName, hasAttribute, oldAttribute);
				}
				/* Il ne faut pas pouvoir ajouter deux fois le meme attributPere d'une meme variableMere.
				 * comme on applique retireVariableMere, ce cas n'arrivera jamais. */
				/* On peut ajouter plusieurs fois une meme variable mere lorsque 
				 * deux attributs d'une variable mere de meme type mais de noms differents
				 * pointent vers la meme valeur par exemple */
				newAttribute.variablesMeres.add(hasAttribute);
				newAttribute.attributsPeres.add(attributeName);
				attribute.set(hasAttribute.valeur, newAttribute.valeur);
				if(Modifier.isStatic(attribute.getModifiers())){
					this.refreshRelatedVariables(hasAttribute);
				}
			}catch(Exception e){
				System.out.println("L'attribut "+attributeName+" de la variable "
						+hasAttribute.name+" n'a pas pu etre modifie");
			}
		}
	}
	
	public ArrayList<ArrayList<Variable>> getConstructorArguments(Constructor cstr){
		ArrayList<ArrayList<Variable>> res = new ArrayList<ArrayList<Variable>>();
		Class[] typeargs = cstr.getParameterTypes();
		if(typeargs.length>0){
			for(int i=0; i<typeargs.length; i++){
				ArrayList<Variable> vars_i = new ArrayList<Variable>();
				Class class_arg_i = typeargs[i];
				for(int j=0; j<this.instances.size(); j++){
					//if(this.instances.get(j).type.getName().equals(class_arg_i.getName())){
					if(this.instances.get(j).type.isAssignableFrom(class_arg_i)){
						vars_i.add(this.instances.get(j));
					}
				}
				res.add(vars_i);
			}
		}
		return res;
	}
	
	public ArrayList<ArrayList<Variable>> getMethodOrConstructorArguments(Class[] typesArguments){
		ArrayList<ArrayList<Variable>> res = new ArrayList<ArrayList<Variable>>();
		if(typesArguments.length>0){
			for(int i=0; i<typesArguments.length; i++){
				ArrayList<Variable> vars_i = new ArrayList<Variable>();
				Class typeArgument_i = typesArguments[i];
				for(int j=0; j<this.instances.size(); j++){
					if(typeArgument_i.isAssignableFrom(this.instances.get(j).type)){
						vars_i.add(this.instances.get(j));
					}
				}
				res.add(vars_i);
			}
		}
		return res;
	}
	
	public ArrayList<Variable> linkedAttributes(Variable culprit, boolean start){
		/* supprime les liens entre une variable et tous ses attributs et realise ensuite 
		 * la meme chose recursivement a chacun de ces attributs qui est de type non primitif */
		ArrayList<Variable> ret = new ArrayList<Variable>();
		for(int i=0; i<this.instances.size(); i++){
			Variable var_i = this.instances.get(i);
			if(start){
				int j=0;
				boolean islinked = false;
				while(j<var_i.variablesMeres.size()){
					if(var_i.variablesMeres.get(j).name.equals(culprit.name)){
						islinked = true;
						var_i.variablesMeres.remove(j);
						var_i.attributsPeres.remove(j);
					}else{
						j++;
					}
				}
				if(islinked){
					ret.add(var_i);
					ArrayList<Variable> ret_rec = this.linkedAttributes(var_i, false);
					for(int k=0; k<ret_rec.size(); k++){
						ret.add(ret_rec.get(k));
					}
				}
			}else{
				boolean islinked = false;
				for(int j=0; j<var_i.variablesMeres.size(); j++){
					if(var_i.variablesMeres.get(j).name.equals(culprit.name)){
						islinked = true;
					}
				}
				if(islinked){
					ret.add(var_i);
					ArrayList<Variable> ret_rec = this.linkedAttributes(var_i, false);
					for(int k=0; k<ret_rec.size(); k++){
						ret.add(ret_rec.get(k));
					}
				}
			}
		}
		
		return ret;
	}
	
	public ArrayList<Variable> removeAttributesFromInstances(Variable culprit, boolean start){
		ArrayList<Variable> ret = new ArrayList<Variable>();
		if(!this.isPrimitif(culprit.type.getName())){
			boolean reset = false;
			int i = 0;
			while(i<this.instances.size()){
				reset = false;
				boolean islinked = false;
				int j=0;
				Variable var_i = this.instances.get(i);
				//System.out.println("HEY LOOK WE'VE REACHED THE "+i+"-TH STEP... GREAT...");
				while(j<var_i.variablesMeres.size()){
					if(var_i.variablesMeres.get(j).name.equals(culprit.name)){
						islinked = true;
						var_i.variablesMeres.remove(j);
						var_i.attributsPeres.remove(j);
						/*System.out.println(culprit.name+" is "+var_i.attributsPeres.get(j)
								+" attribute of "+var_i.name+" i="+i+" j="+j );*/
						if(j<=i){
							reset = true;
						}
					}else{
						/*System.out.println("ON THE "+i+"-TH STEP = "+"NOPE, NO PARENT WITH THE "+j+"-TH VARIABLE WHICH IS "
								+culprit.name);*/
						j++;
					}
				}
				if(islinked){
					System.out.println("STEP "+i+" ABOUT TO ADD THIS SUCKER IN "+var_i.name);
					ret.add(var_i);
					ArrayList<Variable> ret_rec = this.removeAttributesFromInstances(var_i, false);
					for(int k=0; k<ret_rec.size(); k++){
						ret.add(ret_rec.get(k));
					}
				}
				if(reset){
					//System.out.println("TO RESET");
					i=0;
				}else{
					//System.out.println("NOT TO RESET");
					i++;
				}
			}
		}
		return ret;
	}
	
	//----------------------HEEEEERE GOOEEESSSSSS--------------------------------
	public Object callMethodUpon(Method meth, Variable upon, Object[] methargs){
		try{
			ArrayList<Variable> motherVariables = upon.variablesMeres;
			ArrayList<String> fatherAttributes = upon.attributsPeres;
			//Environnement env_copycat = new Environnement();
			//env_copycat.pile = this.pile;
			//ArrayList<Variable> linked_atts = env_copycat.linkedAttributes(upon, true);
			ArrayList<Variable> linked_atts = this.linkedAttributes(upon, true);
			Object retourMethode = meth.invoke(upon.valeur, methargs);
			this.addAttributesToInstances(upon);
			if(this.hasStaticField(upon)){
				this.refreshRelatedVariables(upon);
			}
			return retourMethode;
		}catch(Exception e){
			System.out.println("Echec d'appel de la methode "+upon.toString()+" sur variable "+upon.name);
			Object ret = null;
			return ret;
		}
	}
	//---------------------------------------------------------------------------
	
	public Variable getVariableByName(String namevar){
		Variable res = null;
		for(int k = 0; k<this.instances.size(); k++){
			if(this.instances.get(k).name.equals(namevar)){
				res = this.instances.get(k);
			}
		}
		return res;
	}
	
	public Class getClasseByName(String classname){
		Class res = null;
		int k = 0;
		boolean found = false;
		while((k<this.types.size()) && (!found)){
			if(this.types.get(k).getName().equals(classname)){
				res = this.types.get(k);
				found = true;
			}
			k++;
		}
		return res;
	}
	
	public Poignee getPoigneeByName(String namepgn){
		Poignee res = null;
		for(int k = 0; k<this.pile.size(); k++){
			if(this.pile.get(k).nom.equals(namepgn)){
				res = this.pile.get(k);
			}
		}
		return res;
	}
	
	public void equalsPoigneePoignee(String namepgnleft, String namepgnright){
		Poignee pgnleft = this.getPoigneeByName(namepgnleft);
		Poignee pgnright = this.getPoigneeByName(namepgnright);
		if((pgnleft!=null) && (pgnright!=null) && (pgnleft.typepgn.isAssignableFrom(pgnright.typepgn))){
			if(pgnright.pointeVers!=null){
				if(pgnleft.pointeVers!=null){
					pgnleft.pointeVers.retirePoignee(pgnleft.nom);
				}
				pgnright.pointeVers.poignees.add(pgnleft);
				pgnleft.pointeVers = pgnright.pointeVers;
			}else{
				if(pgnleft.pointeVers!=null){
					pgnleft.pointeVers.retirePoignee(pgnleft.nom);
					pgnleft.pointeVers = null;
				}
			}
		}
	}
	
	public void retireVariableMere(String nomattribut, Variable varMere, Variable varFille){
		int i = 0;
		//boolean found = false;
		//while(i<varFille.variablesMeres.size() && !found){
		while(i<varFille.variablesMeres.size()){
			if(varFille.variablesMeres.get(i).name.equals(varMere.name) 
					&& varFille.attributsPeres.get(i).equals(nomattribut)){
				varFille.variablesMeres.remove(i);
				varFille.attributsPeres.remove(i);
				//found = true;
			}else{
				i++;
			}
		}
	}
	
	public void equalsPoigneeVariable(String namepgn, String namevar){
		Poignee pgn = this.getPoigneeByName(namepgn);
		if(pgn!=null){
			if(namevar.equals("null")){
				if(pgn.pointeVers!=null){
					pgn.pointeVers.retirePoignee(namepgn);
					pgn.pointeVers = null;
				}
			}else{
				Variable var = this.getVariableByName(namevar);
				if(var!=null){
					if(pgn.typepgn.isAssignableFrom(var.type)){
						if(pgn.pointeVers!=null){
							pgn.pointeVers.retirePoignee(namepgn);
						}
						var.poignees.add(pgn);
						pgn.pointeVers = var;
					}
				}
			}
		}
	}
	
	public void mettrePoigneeNull(String namepgn){
		Poignee pgn = this.getPoigneeByName(namepgn);
		if((pgn!=null)&&(pgn.pointeVers!=null)){
			pgn.pointeVers.retirePoignee(namepgn);
			pgn.pointeVers = null;
		}
	}
	
	public void ramasseMiettes(){
		/* supprime les variables sans poignees. Il se peut qu'une variable non primitive
		 * ne soit liee a aucune poignee mais que certains de ses attributs le soient */
		/* il se peut qu'il soit necessaire de faire plusieurs balayages tant qu'une suppression 
		 * de variable est effectuee lors d'un balayage */
		int k = 0;
		boolean modification = true;
		while(modification){
			modification = false;
			while(k < this.instances.size()){
				Variable varMere_k = this.instances.get(k);
				if(varMere_k.poignees.isEmpty() && varMere_k.variablesMeres.isEmpty()){
					/* avant de supprimer l'element, il faut le retirer des listes variablesMeres
					 * de tous ses attributs */
					Field[] allFields_k = Environnement.getAllFields(varMere_k.type);
					for(int i=0; i<allFields_k.length; i++){
						String field_i_name = allFields_k[i].getName();
						for(int j=0; j<this.instances.size(); j++){
							Variable varFille_j = this.instances.get(j);
							this.retireVariableMere(field_i_name, varMere_k, varFille_j);
						}
					}
					modification = true;
					this.instances.remove(k);
				}else{
					k++;
				}
			}
		}
	}
	
	public static boolean estAccessible(Variable var){
		/* toutes les variables proposees doivent etre accessibles,
		 * que ce soit pour changer d'attribut, appeler une methode ou un constructeur */
		boolean accessible = false;
		if(var.poignees.size()>0){
			accessible = true;
		}
		int i=0;
		while((!accessible)&&(i<var.variablesMeres.size())){
			accessible = estAccessible(var.variablesMeres.get(i));
			i++;
		}
		return accessible;
	}
	
	public ArrayList<Variable> variablesContenantAttributs(Variable var){
		ArrayList<Variable> res = new ArrayList<Variable>();
		for(int i=0; i<this.instances.size(); i++){
			Variable var_i = this.instances.get(i);
			if(var.possedeAttributDans(var_i)){
				res.add(var_i);
			}
		}
		return res;
	}
	
	public boolean hasStaticField(Variable var){
		/* verifie recursivement si une variable ainsi que toutes les variables ayant pour valeurs
		 * les attributs de cette variable possedent au moins un attribut statique */
		boolean has = false;
		if(!this.isPrimitif(var.type.getName())){
			Field[] allFields = Environnement.getAllFields(var.type);
			for(int i=0; i<allFields.length; i++){
				if(Modifier.isStatic(allFields[i].getModifiers())){
					has = true;
				}
			}
			if(!has){
				/* appel recursif sur chaque variable contenant la valeur d'un attribut de var */
				ArrayList<Variable> varsAttributs = this.variablesContenantAttributs(var);
				int i=0;
				while((!has)&&(i<varsAttributs.size())){
					has = this.hasStaticField(varsAttributs.get(i));
					i++;
				}
			}
		}
		return has;
	}
	
	public void refreshRelatedVariables(Variable var){
		for(int i=0; i<this.instances.size(); i++){
			Variable var_i = this.instances.get(i);
			if((!var_i.name.equals(var.name))&&
					((var_i.type.isAssignableFrom(var.type)) || (var.type.isAssignableFrom(var.type)))){
				/* met a jour les liens des variables de type compatible avec celui de var */
				ArrayList<Variable> linked_atts = this.linkedAttributes(var_i, true);
				this.addAttributesToInstances(var_i);
			}
		}
		
	}
	
	public static Field[] getAllFields(Class type){
		/* renvoie toutes les variables declarees dans la classe et toutes ses superclasses */
		Field[] fields = type.getDeclaredFields();
        if(type.getSuperclass() != null) {
        	Field[] superfields = getAllFields(type.getSuperclass());
        	Field[] res = new Field[fields.length+superfields.length];
        	for(int i=0; i<fields.length; i++){
        		res[i] = fields[i];
        	}
        	for(int i=0; i<superfields.length; i++){
        		res[fields.length+i] = superfields[i];
        	}
        	return res;
        }else{
        	return fields;
        }
	}
	
	public ArrayList<Variable> cloneInstances(){
		ArrayList<Variable> snapshot = new ArrayList<Variable>();
		for(int i=0; i<this.instances.size(); i++){
			snapshot.add(this.instances.get(i).cloneVariable());
		}
		return snapshot;
	}
	
	public ArrayList<Poignee> clonePile(){
		ArrayList<Poignee> stack = new ArrayList<Poignee>();
		for(int i=0; i<this.pile.size(); i++){
			stack.add(this.pile.get(i).clonePoignee());
		}
		return stack;
	}
	
	public static void main(String[] args) {
		
		/*Point p1 = new Point(1,1);
		Point2 p2 = new Point2(); 
		Segment s = new Segment(p1,p2);
		Class point = p1.getClass();
		Class point2 = p2.getClass();
		Class segment = s.getClass();
		Class entier = p1.getClass().getDeclaredFields()[0].getType();
		Integer i = 2;
		Class entierbis = i.getClass();
		String ch = "";
		Class chaine = ch.getClass();*/
		
		Environnement env = new Environnement();
		
		JFileChooser fChooser = new JFileChooser("./xml");
		FileNameExtensionFilter filter = new FileNameExtensionFilter("Fichiers XML", "xml");
		fChooser.setFileFilter(filter);
		fChooser.showOpenDialog(null);
		System.out.println(fChooser.getSelectedFile().getPath());	
		
		ParseurXML parseur = new ParseurXML(fChooser.getSelectedFile().getPath());
		ArrayList<Class> drawable = parseur.extraitClassesDessinables();
		ArrayList<String> primitifs = parseur.extraitClassesPrimitives();
		
		env.types = drawable;
		env.typesprimitifs = primitifs;
		
		/*
		env.types.add(segment);
		env.types.add(point);
		env.types.add(point2);
		*/
		//env.types.add(entier);
		//env.types.add(chaine);
		/*
		env.typesprimitifs.add(entier.getName());
		env.typesprimitifs.add(entierbis.getName());
		env.typesprimitifs.add(chaine.getName());
		*/
		/*
		for(int k=0; k < env.typesprimitifs.size(); k++){
			System.out.println("Type primitif "+k+" "+env.typesprimitifs.get(k));
		}
		*/
		/*
		for(int k=0; k<segment.getDeclaredMethods().length; k++){
			System.out.println("Methode "+k+" "+segment.getDeclaredMethods()[k].toString());
		}
		for(int k=0; k<point.getConstructors().length; k++){
			System.out.println("Constructeur "+k+" "+point.getConstructors()[k].toString());
		}
		Object[] argcstr = new Object[0];
		env.createVariable(point.getConstructors()[0], argcstr);
		env.createVariable(point.getConstructors()[0], argcstr);
		
		Object[] argseg = new Object[segment.getConstructors()[0].getParameterTypes().length];
		argseg[0] = env.getVariableByName("Point0").valeur;
		argseg[1] = env.getVariableByName("Point1").valeur;
		env.createVariable(segment.getConstructors()[0], argseg);
		
		Object[] argseg2 = new Object[segment.getConstructors()[1].getParameterTypes().length];
		argseg2[0] = env.getVariableByName("Point1").valeur;
		env.createVariable(segment.getConstructors()[1], argseg2);
		
		Method meth = segment.getDeclaredMethods()[0];
		System.out.println(meth.toString()+"#########$$$$$$$$$$$");
		Object[] methargs = new Object[0];
		try{
			Object retour = meth.invoke(env.getVariableByName("Segment3").valeur, methargs);
			System.out.println("HEY IS THIS ... BUGGER-ALL ?! "+(retour ==null));
		}catch(Exception e){
			System.out.println("FUCK NOOOOOO");
		}
		*/
		/*
		ArrayList<Variable> sousattributs = new ArrayList<Variable>();
		sousattributs = env.removeAttributesFromInstances(env.getVariableByName("Segment3"), true);
		sousattributs = env.linkedAttributes(env.getVariableByName("Segment3"), true);
		for(int k=0; k<sousattributs.size(); k++){
			Variable var_k = sousattributs.get(k);
			System.out.println("IS LINKED "+var_k.name+" number "+k);
			System.out.println("L'attribut "+var_k.name+" est lie a "+var_k.variablesMeres.size()+" variables meres");
			for(int q = 0; q<var_k.variablesMeres.size(); q++){
				System.out.println(var_k.variablesMeres.get(q).name+" %$% "+var_k.attributsPeres.get(q));
			}
		}
		*/
		//env.addAttributesToInstances(env.getVariableByName("Segment3"));
		
		/*
		Object[] argseg4 = new Object[segment.getConstructors()[0].getParameterTypes().length];
		argseg4[0] = env.getVariableByName("Segment2").valeur;
		argseg4[1] = env.getVariableByName("Segment3").valeur;
		env.createVariable(segment.getConstructors()[0], argseg4);
		Variable point1 = env.getVariableByName("Point1");
		*/
		//ChoixArguments choose = new ChoixArguments(env.getConstructorArguments(segment.getConstructors()[0]));
		//env.changeAttribute("pntl", seg3, point1);
		/*
		for(int p=0; p<env.instances.size(); p++){
			Variable varp = env.instances.get(p);
			for(int k=0; k < varp.variablesMeres.size(); k++){
				System.out.println(varp.name+" est attribut de "+varp.variablesMeres.get(k).name);
			}
		}
		
		for(int k=0; k<segment.getConstructors().length; k++){
			System.out.println("Constructeur num"+k+" "+segment.getConstructors()[k].toString());
		}
		ArrayList<ArrayList<Variable>> cstrargs = env.getConstructorArguments(segment.getConstructors()[0]);
		for(int k=0; k<cstrargs.size(); k++){
			for(int p=0; p<cstrargs.get(k).size(); p++){
				System.out.println("Argument "+k+" du constructeur : "+cstrargs.get(k).get(p).type.getName()+
						" "+cstrargs.get(k).get(p).name);
			}
		}*/
		/*
		env.equalsPoigneeVariable("p1","Segment0.pointB");
		env.mettrePoigneeNull("p0");
		env.ramasseMiettes();
		*/
		/*
		for(int k=0; k<env.instances.size(); k++){
			Variable vark = env.instances.get(k);
			System.out.println("Variable num"+k+" "+vark.type.getSimpleName()+" nom = "+vark.name);
		}
		for(int k=0; k<env.pile.size(); k++){
			if(env.pile.get(k).pointeVers!=null){
				System.out.println(env.pile.get(k).nom+" -> "+env.pile.get(k).pointeVers.name);
			}else{
				System.out.println(env.pile.get(k).nom + " -> null");
			}
		}
		*/
		DrawEnvironnement drawenv = new DrawEnvironnement(env);
		/*
		JFrame yeah = new JFrame();
		Container content = yeah.getContentPane();
		content.setBackground(Color.WHITE);
	    content.setLayout(new BorderLayout());
	    content.add(drawenv,BorderLayout.CENTER);
	    yeah.pack();
	    yeah.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		yeah.setVisible(true);
		*/
		/*
		for(int k=0; k<drawenv.env.instances.size(); k++){
			System.out.println("Variable num"+k+" "+drawenv.env.instances.get(k).type.getName()
			+" "+drawenv.env.instances.get(k).name);
		}
		*/
		GUI gui = new GUI(drawenv);
	}
}
